package jmind.core.mongodb;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import jmind.base.util.DateUtil;
import jmind.base.util.GlobalConstants;

import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MapReduceOutput;
import com.mongodb.WriteResult;

/**
 * 基于对 DBCollection 的封装
 * @author weibo.xie
 * 2011-12-1
 */
public class MongoCollection {
    public static final String ID = "_id";
    public static final int ONE = 1;

    private DBCollection coll;

    public String name = this.getClass().getSimpleName();

    public MongoCollection(DB db) {
        this.coll = db.getCollection(name);
    }

    public MongoCollection(DB db, String suffix) {
        this.coll = db.getCollection(name + GlobalConstants.DASH + suffix);
    }

    public String getToday() {
        return DateUtil.Today;
    }

    public Collection<String> keys() {
        return getColl().findOne().keySet();
    }

    public DBCollection getColl() {
        return coll;
    }

    /**
     * 
     * @return
     */
    protected BasicDBObjectBuilder builder() {
        return BasicDBObjectBuilder.start();
    }

    /**
     * 
     * @param key
     * @param val
     * @return
     */
    protected BasicDBObjectBuilder builder(String key, Object val) {
        return BasicDBObjectBuilder.start(key, val);
    }

    public void save(DBObject o) {
        getColl().save(o);
    }

    public void insert(DBObject... arr) {
        getColl().insert(arr);
    }

    public void insert(List<DBObject> arr) {
        getColl().insert(arr);
    }

    /**
     * 
     * @param q
     * @param o
     * @return
     */
    public WriteResult update(DBObject q, DBObject o) {
        return getColl().update(q, builder("$set", o).get());
    }

    public void updateById(DBObject update) {
        Object id = update.removeField(ID);
        if (id != null) {
            getColl().update(builder(ID, id).get(), builder("$set", update).get());
        }

    }

    /**
     * 有则更新，无则插入
     * @param _id
     * @param o
     * @return
     */
    public WriteResult set(Object _id, DBObject o) {
        return getColl().update(builder(ID, _id).get(), builder("$set", o).get(), true, false);
    }

    /**
     * 
     * @param primaryKey
     * @param field
     * @param num
     */
    public void inc(Object primaryKey, String field, int num) {

        DBObject update = new BasicDBObject(field, num);
        /**
         * 第一个 true  有则跟新，无则插入
         * 第二个 只跟新一个 或者都跟新
         */
        getColl().update(new BasicDBObject(ID, primaryKey), new BasicDBObject("$inc", update), true, false);

    }

    /**
     * 根据主键删除
     * @param primaryKey
     */
    public void remove(Object primaryKey) {
        getColl().remove(builder(ID, primaryKey).get());
    }

    /**
     * Between 
     * @param start
     * @param end
     * @return
     */
    public List<DBObject> betweenAnd(Object start, Object end) {
        DBObject query = builder(ID, builder("$gte", start).add("$lte", end).get()).get();
        return getColl().find(query).toArray();

    }

    /**
     * 查找所有
     * @return
     */
    public List<DBObject> find(DBObject query) {
        return getColl().find(query).toArray();
    }

    public List<DBObject> find(DBObject query, int start, int limit) {
        return getColl().find(query).skip(start).limit(limit).toArray();
    }

    /**
     * 
     * @param primaryKey主键查找
     * @return
     */
    public DBObject findOne(Object primaryKey) {
        return getColl().findOne(primaryKey);
    }

    /**
     * 
     * @param o 
     * @return
     */
    public DBObject findOne(DBObject o) {

        return getColl().findOne(o);
    }

    /**
     * 
     * @param obj
     * @param fields
     * @return
     */
    public DBObject findOne(Object obj, DBObject fields) {
        return getColl().findOne(obj, fields);
    }

    /**
    * @param field 字段
    * @return 最大值
    */
    public int getMax(String field) {
        Integer num = 0;
        DBCursor cursor = getColl().find(null, builder(field, ONE).get()).sort(builder(field, -ONE).get()).limit(ONE);
        if (cursor.hasNext()) {
            DBObject next = cursor.next();
            num = (Integer) next.get(field);
        }
        return num;
    }

    /**
     * 
     * @param field 字段最小值
     * @return
     */
    public int getMin(String field) {
        Integer num = 0;
        DBCursor cursor = getColl().find(null, builder(field, ONE).get()).sort(builder(field, ONE).get()).limit(ONE);
        if (cursor.hasNext()) {
            DBObject next = cursor.next();
            num = (Integer) next.get(field);
        }
        return num;

    }

    /**
     * 得到某字段的和
     * @param field
     * @param query 查询条件
     * @return
     */
    public int sum(String field, DBObject query) {
        String map = "function(){ var f=this." + field + "; if(f){emit(1, f);} }";
        String reduce = " function(k,vals) {var count=0 ;for(var i in vals){count+=vals[i];	}return count}";
        String collName = "tmp_" + field;
        MapReduceOutput result = getColl().mapReduce(map, reduce, collName, query);
        Iterator<DBObject> iterator = result.results().iterator();
        if (iterator.hasNext()) {
            Object value = result.results().iterator().next().get("value");
            result.drop();
            if (value instanceof Integer) {
                return (Integer) value;
            } else if (value instanceof Double)
                return ((Double) value).intValue();
            else
                return Integer.parseInt(value.toString());
        } else {
            result.drop();
            return 0;
        }

    }

    /**
     * 
     * @return
     */
    public long count() {
        return getColl().count();
    }

    /**
     * 
     * @param field 字段
     * @param max 条数
     * @return
     */
    public List<DBObject> getTopByField(String field, int max) {
        DBCursor cursor = getColl().find(null, new BasicDBObject(field, ONE)).sort(new BasicDBObject(field, -ONE))
                .limit(max);
        return cursor.toArray();
    }

    /**
     * 
     * @param coll
     * @param field
     * @param max
     * @return
     */
    public List<DBObject> getTopByField(DBCollection coll, String field, int max) {
        DBCursor cursor = coll.find(null, new BasicDBObject(field, ONE)).sort(new BasicDBObject(field, -ONE))
                .limit(max);
        return cursor.toArray();
    }

}
